package com.yangtao.framework.mapping.config;

import com.yangtao.framework.util.DataType;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * @auther: 杨涛
 * Date: 11-4-20
 * Time: 下午5:11
 * @version: 1.0
 */
public class MappingConfig {
	/**
	 * 映射配置的Id
	 */
	private String mappingId;
	/**
	 * 匹配方向
	 * one-way 单向
	 * two-way 双向
	 */
	private String direction;

	/**
	 * 映射源类的类型
	 */
	private String srcClassType;

	/**
	 * 映射的目标类类型
	 */
	private String destClassType;

	/**
	 * 包含的属性列表
	 */
	private List<PropertyConfig> includeList;
	/**
	 * 过滤的属性列表
	 */
	private List<PropertyConfig> excludeList;
	/**
	 * 实际生效的属性映射列表
	 */
	private List<PropertyConfig> actualPropertyMappingList;

	/**
	 * 所有符合条件的映射列表
	 */
	private List<PropertyConfig> allMatchedList;

	/**
	 * 计算实际生效的属性复制列表
	 */
	public void calculateActualPropertyMappingList() throws CloneNotSupportedException {
		//如果设置了include，就是用include
		if (this.getIncludeList() != null && this.getIncludeList().size() > 0) {
			this.setActualPropertyMappingList(this.getIncludeList());
		}
		//如果没有是用include，就用全部的映射属性-过滤的映射属性
		else {
			// 取得所有的属性列表
			List<PropertyConfig> allMatchedProperty = getAllMatchedProperty();
			this.setAllMatchedList(allMatchedProperty);
			final List<PropertyConfig> copyedAllMatched = new LinkedList<PropertyConfig>();
			for (PropertyConfig propertyConfig : allMatchedProperty) {
				PropertyConfig clone = propertyConfig.clone();
				copyedAllMatched.add(clone);
			}
			//如果过滤列表不为空，那么判断过滤列表
			final List<PropertyConfig> excludesList = this.getExcludeList();

			if (excludesList != null && excludesList.size() > 0) {
				//使用apache的过滤器
				CollectionUtils.filter(copyedAllMatched, new Predicate() {
					@Override
					public boolean evaluate(Object object) {
						for (PropertyConfig property : excludesList) {
							if (object.equals(property))
								return false;
						}
						return true;
					}
				});
			}
			this.setActualPropertyMappingList(copyedAllMatched);
		}
	}

	/**
	 * 取得源对象和目标对象中的属性名称相同的列
	 *
	 * @return 源对象和目标对象中的属性名称相同的列
	 * @throws ClassNotFoundException
	 */
	public List<PropertyConfig> getAllMatchedProperty() {
		final List<PropertyConfig> ret = new ArrayList<PropertyConfig>();
		try {
			ReflectionUtils.doWithMethods(Class.forName(srcClassType), new ReflectionUtils.MethodCallback() {
				@Override
				public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
					//如果是get方法
					if (method.getName().startsWith("get")) {
						//取得属性名称
						String fieldName = StringUtils.uncapitalize(method.getName().substring(3));
						boolean mateched = true;
						PropertyConfig propertyConfig = new PropertyConfig();
						propertyConfig.setSrcPropertyName(fieldName);
						propertyConfig.setSrcPropertyType(DataType.getDataType(method.getReturnType()));
						//如果源类和目标类是同一个类，那么目标属性就和源属性一样
						if (srcClassType.equals(destClassType)) {
							propertyConfig.setDestPropertyName(propertyConfig.getSrcPropertyName());
							propertyConfig.setDestPropertyType(propertyConfig.getSrcPropertyType());
						}
						//否则，取得目标类的相同属性名的filed
						else {
							try {
								Method destMethod = ReflectionUtils.findMethod(Class.forName(destClassType), method.getName());
								if (destMethod != null) {
									propertyConfig.setDestPropertyName(fieldName);
									propertyConfig.setDestPropertyType(DataType.getDataType(destMethod.getReturnType()));
								} else {
									mateched = false;
								}
							} catch (ClassNotFoundException e) {
								e.printStackTrace();
							}
						}
						if (mateched) {
							ret.add(propertyConfig);
						}
					}
				}
			});
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return ret;
	}

	public String getMappingId() {
		return mappingId;
	}

	public void setMappingId(String mappingId) {
		this.mappingId = mappingId;
	}

	public String getDirection() {
		return direction;
	}

	public void setDirection(String direction) {
		this.direction = direction;
	}

	public String getSrcClassType() {
		return srcClassType;
	}

	public void setSrcClassType(String srcClassType) {
		this.srcClassType = srcClassType;
	}

	public String getDestClassType() {
		return destClassType;
	}

	public void setDestClassType(String destClassType) {
		this.destClassType = destClassType;
	}

	public List<PropertyConfig> getIncludeList() {
		return includeList;
	}

	public void setIncludeList(List<PropertyConfig> includeList) {
		this.includeList = includeList;
	}

	public List<PropertyConfig> getExcludeList() {
		return excludeList;
	}

	public void setExcludeList(List<PropertyConfig> excludeList) {
		this.excludeList = excludeList;
	}

	public List<PropertyConfig> getActualPropertyMappingList() {
		return actualPropertyMappingList;
	}

	public void setActualPropertyMappingList(List<PropertyConfig> actualPropertyMappingList) {
		this.actualPropertyMappingList = actualPropertyMappingList;
	}

	public List<PropertyConfig> getAllMatchedList() {
		return allMatchedList;
	}

	public void setAllMatchedList(List<PropertyConfig> allMatchedList) {
		this.allMatchedList = allMatchedList;
	}
}
